"""
文件处理器 - 支持多种文件格式的文本提取
"""
import os
import json
import logging
from pathlib import Path
from typing import Dict, List, Optional, Tuple, Any
from datetime import datetime
import mimetypes

# PDF处理
try:
    import PyPDF2
    import pdfplumber
    PDF_AVAILABLE = True
except ImportError:
    PDF_AVAILABLE = False

# Word文档处理
try:
    from docx import Document
    DOCX_AVAILABLE = True
except ImportError:
    DOCX_AVAILABLE = False

# Excel处理
try:
    import openpyxl
    import pandas as pd
    EXCEL_AVAILABLE = True
except ImportError:
    EXCEL_AVAILABLE = False

# PowerPoint处理
try:
    from pptx import Presentation
    PPTX_AVAILABLE = True
except ImportError:
    PPTX_AVAILABLE = False

# 图像OCR处理
try:
    from PIL import Image
    import pytesseract
    OCR_AVAILABLE = True
except ImportError:
    OCR_AVAILABLE = False

from ..config.settings import FILE_CONFIG

logger = logging.getLogger(__name__)

class FileHandler:
    """文件处理器基类"""
    
    def __init__(self):
        self.supported_extensions = FILE_CONFIG["allowed_extensions"]
        self.max_file_size = FILE_CONFIG["max_file_size"]
    
    def can_handle(self, file_path: str) -> bool:
        """检查是否可以处理该文件"""
        if not os.path.exists(file_path):
            return False
        
        # 检查文件大小
        file_size = os.path.getsize(file_path)
        if file_size > self.max_file_size:
            logger.warning(f"文件过大: {file_path} ({file_size} bytes)")
            return False
        
        # 检查文件扩展名
        ext = Path(file_path).suffix.lower()
        return ext in self.supported_extensions
    
    def extract_text(self, file_path: str) -> Dict[str, Any]:
        """提取文件文本内容"""
        raise NotImplementedError
    
    def get_metadata(self, file_path: str) -> Dict[str, Any]:
        """获取文件元数据"""
        raise NotImplementedError

class PDFHandler(FileHandler):
    """PDF文件处理器"""
    
    def __init__(self):
        super().__init__()
        if not PDF_AVAILABLE:
            raise ImportError("PDF处理库未安装: PyPDF2, pdfplumber")
    
    def extract_text(self, file_path: str) -> Dict[str, Any]:
        """提取PDF文本内容"""
        try:
            text_content = []
            metadata = {}
            
            # 使用pdfplumber提取文本和表格
            with pdfplumber.open(file_path) as pdf:
                metadata["page_count"] = len(pdf.pages)
                metadata["pages"] = []
                
                for page_num, page in enumerate(pdf.pages):
                    page_data = {
                        "page_number": page_num + 1,
                        "text": "",
                        "tables": [],
                        "images": []
                    }
                    
                    # 提取文本
                    text = page.extract_text()
                    if text:
                        page_data["text"] = text.strip()
                        text_content.append(f"第{page_num + 1}页:\n{text.strip()}")
                    
                    # 提取表格
                    tables = page.extract_tables()
                    for table_num, table in enumerate(tables):
                        if table:
                            table_text = self._table_to_text(table)
                            page_data["tables"].append(table_text)
                            text_content.append(f"第{page_num + 1}页表格{table_num + 1}:\n{table_text}")
                    
                    metadata["pages"].append(page_data)
            
            # 使用PyPDF2获取文档信息
            with open(file_path, 'rb') as file:
                pdf_reader = PyPDF2.PdfReader(file)
                info = pdf_reader.metadata
                if info:
                    metadata["title"] = info.get('/Title', '')
                    metadata["author"] = info.get('/Author', '')
                    metadata["subject"] = info.get('/Subject', '')
                    metadata["creator"] = info.get('/Creator', '')
                    metadata["producer"] = info.get('/Producer', '')
            
            return {
                "text": "\n\n".join(text_content),
                "metadata": metadata,
                "success": True
            }
            
        except Exception as e:
            logger.error(f"PDF文本提取失败: {file_path}, 错误: {e}")
            return {
                "text": "",
                "metadata": {},
                "success": False,
                "error": str(e)
            }
    
    def _table_to_text(self, table: List[List[str]]) -> str:
        """将表格转换为文本"""
        if not table:
            return ""
        
        text_lines = []
        for row in table:
            if row:
                # 过滤空值并连接
                row_text = " | ".join([str(cell).strip() if cell else "" for cell in row])
                if row_text.strip():
                    text_lines.append(row_text)
        
        return "\n".join(text_lines)
    
    def get_metadata(self, file_path: str) -> Dict[str, Any]:
        """获取PDF元数据"""
        try:
            with open(file_path, 'rb') as file:
                pdf_reader = PyPDF2.PdfReader(file)
                info = pdf_reader.metadata
                
                metadata = {
                    "file_type": "pdf",
                    "page_count": len(pdf_reader.pages),
                    "file_size": os.path.getsize(file_path),
                    "created_time": None,
                    "modified_time": None
                }
                
                if info:
                    metadata.update({
                        "title": info.get('/Title', ''),
                        "author": info.get('/Author', ''),
                        "subject": info.get('/Subject', ''),
                        "creator": info.get('/Creator', ''),
                        "producer": info.get('/Producer', '')
                    })
                
                return metadata
                
        except Exception as e:
            logger.error(f"获取PDF元数据失败: {file_path}, 错误: {e}")
            return {"file_type": "pdf", "error": str(e)}

class DOCXHandler(FileHandler):
    """Word文档处理器"""
    
    def __init__(self):
        super().__init__()
        if not DOCX_AVAILABLE:
            raise ImportError("Word文档处理库未安装: python-docx")
    
    def extract_text(self, file_path: str) -> Dict[str, Any]:
        """提取Word文档文本内容"""
        try:
            doc = Document(file_path)
            text_content = []
            metadata = {
                "paragraphs": [],
                "tables": [],
                "sections": []
            }
            
            # 提取段落
            for para in doc.paragraphs:
                if para.text.strip():
                    text_content.append(para.text.strip())
                    metadata["paragraphs"].append({
                        "text": para.text.strip(),
                        "style": para.style.name if para.style else ""
                    })
            
            # 提取表格
            for table in doc.tables:
                table_text = []
                for row in table.rows:
                    row_text = " | ".join([cell.text.strip() for cell in row.cells])
                    if row_text.strip():
                        table_text.append(row_text)
                
                if table_text:
                    table_content = "\n".join(table_text)
                    text_content.append(f"表格:\n{table_content}")
                    metadata["tables"].append(table_content)
            
            return {
                "text": "\n\n".join(text_content),
                "metadata": metadata,
                "success": True
            }
            
        except Exception as e:
            logger.error(f"Word文档文本提取失败: {file_path}, 错误: {e}")
            return {
                "text": "",
                "metadata": {},
                "success": False,
                "error": str(e)
            }
    
    def get_metadata(self, file_path: str) -> Dict[str, Any]:
        """获取Word文档元数据"""
        try:
            doc = Document(file_path)
            core_props = doc.core_properties
            
            metadata = {
                "file_type": "docx",
                "paragraph_count": len(doc.paragraphs),
                "table_count": len(doc.tables),
                "section_count": len(doc.sections),
                "file_size": os.path.getsize(file_path)
            }
            
            if core_props:
                metadata.update({
                    "title": core_props.title or "",
                    "author": core_props.author or "",
                    "subject": core_props.subject or "",
                    "created_time": core_props.created.isoformat() if core_props.created else None,
                    "modified_time": core_props.modified.isoformat() if core_props.modified else None
                })
            
            return metadata
            
        except Exception as e:
            logger.error(f"获取Word文档元数据失败: {file_path}, 错误: {e}")
            return {"file_type": "docx", "error": str(e)}

class ExcelHandler(FileHandler):
    """Excel文件处理器"""
    
    def __init__(self):
        super().__init__()
        if not EXCEL_AVAILABLE:
            raise ImportError("Excel处理库未安装: openpyxl, pandas")
    
    def extract_text(self, file_path: str) -> Dict[str, Any]:
        """提取Excel文件文本内容"""
        try:
            text_content = []
            metadata = {
                "sheets": [],
                "total_rows": 0,
                "total_columns": 0
            }
            
            # 读取所有工作表
            workbook = openpyxl.load_workbook(file_path, data_only=True)
            
            for sheet_name in workbook.sheetnames:
                sheet = workbook[sheet_name]
                sheet_data = {
                    "name": sheet_name,
                    "rows": sheet.max_row,
                    "columns": sheet.max_column,
                    "content": []
                }
                
                # 提取单元格内容
                for row in sheet.iter_rows(values_only=True):
                    row_text = []
                    for cell in row:
                        if cell is not None:
                            row_text.append(str(cell).strip())
                    
                    if row_text:
                        row_content = " | ".join(row_text)
                        text_content.append(f"{sheet_name} - {row_content}")
                        sheet_data["content"].append(row_content)
                
                metadata["sheets"].append(sheet_data)
                metadata["total_rows"] += sheet.max_row
                metadata["total_columns"] = max(metadata["total_columns"], sheet.max_column)
            
            return {
                "text": "\n".join(text_content),
                "metadata": metadata,
                "success": True
            }
            
        except Exception as e:
            logger.error(f"Excel文件文本提取失败: {file_path}, 错误: {e}")
            return {
                "text": "",
                "metadata": {},
                "success": False,
                "error": str(e)
            }
    
    def get_metadata(self, file_path: str) -> Dict[str, Any]:
        """获取Excel文件元数据"""
        try:
            workbook = openpyxl.load_workbook(file_path, read_only=True)
            
            metadata = {
                "file_type": "excel",
                "sheet_count": len(workbook.sheetnames),
                "sheet_names": workbook.sheetnames,
                "file_size": os.path.getsize(file_path)
            }
            
            # 获取每个工作表的信息
            sheets_info = []
            for sheet_name in workbook.sheetnames:
                sheet = workbook[sheet_name]
                sheets_info.append({
                    "name": sheet_name,
                    "rows": sheet.max_row,
                    "columns": sheet.max_column
                })
            
            metadata["sheets_info"] = sheets_info
            
            return metadata
            
        except Exception as e:
            logger.error(f"获取Excel文件元数据失败: {file_path}, 错误: {e}")
            return {"file_type": "excel", "error": str(e)}

class PPTXHandler(FileHandler):
    """PowerPoint文件处理器"""
    
    def __init__(self):
        super().__init__()
        if not PPTX_AVAILABLE:
            raise ImportError("PowerPoint处理库未安装: python-pptx")
    
    def extract_text(self, file_path: str) -> Dict[str, Any]:
        """提取PowerPoint文件文本内容"""
        try:
            prs = Presentation(file_path)
            text_content = []
            metadata = {
                "slides": [],
                "slide_count": len(prs.slides)
            }
            
            for slide_num, slide in enumerate(prs.slides):
                slide_text = []
                slide_data = {
                    "slide_number": slide_num + 1,
                    "shapes": []
                }
                
                for shape in slide.shapes:
                    if hasattr(shape, "text") and shape.text.strip():
                        slide_text.append(shape.text.strip())
                        slide_data["shapes"].append({
                            "type": shape.shape_type,
                            "text": shape.text.strip()
                        })
                
                if slide_text:
                    slide_content = f"第{slide_num + 1}页:\n" + "\n".join(slide_text)
                    text_content.append(slide_content)
                
                metadata["slides"].append(slide_data)
            
            return {
                "text": "\n\n".join(text_content),
                "metadata": metadata,
                "success": True
            }
            
        except Exception as e:
            logger.error(f"PowerPoint文件文本提取失败: {file_path}, 错误: {e}")
            return {
                "text": "",
                "metadata": {},
                "success": False,
                "error": str(e)
            }
    
    def get_metadata(self, file_path: str) -> Dict[str, Any]:
        """获取PowerPoint文件元数据"""
        try:
            prs = Presentation(file_path)
            core_props = prs.core_properties
            
            metadata = {
                "file_type": "pptx",
                "slide_count": len(prs.slides),
                "file_size": os.path.getsize(file_path)
            }
            
            if core_props:
                metadata.update({
                    "title": core_props.title or "",
                    "author": core_props.author or "",
                    "subject": core_props.subject or "",
                    "created_time": core_props.created.isoformat() if core_props.created else None,
                    "modified_time": core_props.modified.isoformat() if core_props.modified else None
                })
            
            return metadata
            
        except Exception as e:
            logger.error(f"获取PowerPoint文件元数据失败: {file_path}, 错误: {e}")
            return {"file_type": "pptx", "error": str(e)}

class ImageHandler(FileHandler):
    """图像文件处理器（OCR）"""
    
    def __init__(self):
        super().__init__()
        if not OCR_AVAILABLE:
            raise ImportError("图像OCR处理库未安装: pillow, pytesseract")
    
    def extract_text(self, file_path: str) -> Dict[str, Any]:
        """提取图像文本内容（OCR）"""
        try:
            image = Image.open(file_path)
            
            # 配置OCR
            custom_config = r'--oem 3 --psm 6'
            
            # 执行OCR
            text = pytesseract.image_to_string(image, config=custom_config, lang='chi_sim+eng')
            
            metadata = {
                "image_size": image.size,
                "image_mode": image.mode,
                "ocr_confidence": None  # pytesseract不直接提供置信度
            }
            
            return {
                "text": text.strip(),
                "metadata": metadata,
                "success": True
            }
            
        except Exception as e:
            logger.error(f"图像OCR提取失败: {file_path}, 错误: {e}")
            return {
                "text": "",
                "metadata": {},
                "success": False,
                "error": str(e)
            }
    
    def get_metadata(self, file_path: str) -> Dict[str, Any]:
        """获取图像文件元数据"""
        try:
            image = Image.open(file_path)
            
            metadata = {
                "file_type": "image",
                "image_size": image.size,
                "image_mode": image.mode,
                "file_size": os.path.getsize(file_path)
            }
            
            # 获取EXIF信息
            if hasattr(image, '_getexif') and image._getexif():
                exif = image._getexif()
                if exif:
                    metadata["exif"] = exif
            
            return metadata
            
        except Exception as e:
            logger.error(f"获取图像文件元数据失败: {file_path}, 错误: {e}")
            return {"file_type": "image", "error": str(e)}

class TextHandler(FileHandler):
    """文本文件处理器"""
    
    def __init__(self):
        super().__init__()
    
    def extract_text(self, file_path: str) -> Dict[str, Any]:
        """提取文本文件内容"""
        try:
            # 尝试不同的编码
            encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']
            text = ""
            
            for encoding in encodings:
                try:
                    with open(file_path, 'r', encoding=encoding) as file:
                        text = file.read()
                    break
                except UnicodeDecodeError:
                    continue
            
            if not text:
                # 如果所有编码都失败，使用二进制模式读取
                with open(file_path, 'rb') as file:
                    text = file.read().decode('utf-8', errors='ignore')
            
            metadata = {
                "encoding": encoding if 'encoding' in locals() else 'unknown',
                "line_count": len(text.splitlines())
            }
            
            return {
                "text": text,
                "metadata": metadata,
                "success": True
            }
            
        except Exception as e:
            logger.error(f"文本文件提取失败: {file_path}, 错误: {e}")
            return {
                "text": "",
                "metadata": {},
                "success": False,
                "error": str(e)
            }
    
    def get_metadata(self, file_path: str) -> Dict[str, Any]:
        """获取文本文件元数据"""
        try:
            with open(file_path, 'r', encoding='utf-8') as file:
                lines = file.readlines()
            
            metadata = {
                "file_type": "text",
                "line_count": len(lines),
                "char_count": sum(len(line) for line in lines),
                "file_size": os.path.getsize(file_path)
            }
            
            return metadata
            
        except Exception as e:
            logger.error(f"获取文本文件元数据失败: {file_path}, 错误: {e}")
            return {"file_type": "text", "error": str(e)}

class FileHandlerFactory:
    """文件处理器工厂"""
    
    _handlers = {}
    
    @classmethod
    def register_handler(cls, extension: str, handler_class):
        """注册文件处理器"""
        cls._handlers[extension.lower()] = handler_class
    
    @classmethod
    def get_handler(cls, file_path: str) -> Optional[FileHandler]:
        """获取文件处理器"""
        ext = Path(file_path).suffix.lower()
        handler_class = cls._handlers.get(ext)
        
        if handler_class:
            try:
                return handler_class()
            except ImportError as e:
                logger.warning(f"处理器不可用: {ext}, 错误: {e}")
                return None
        
        return None
    
    @classmethod
    def extract_text(cls, file_path: str) -> Dict[str, Any]:
        """提取文件文本内容"""
        handler = cls.get_handler(file_path)
        if handler:
            return handler.extract_text(file_path)
        else:
            return {
                "text": "",
                "metadata": {},
                "success": False,
                "error": f"不支持的文件类型: {Path(file_path).suffix}"
            }
    
    @classmethod
    def get_metadata(cls, file_path: str) -> Dict[str, Any]:
        """获取文件元数据"""
        handler = cls.get_handler(file_path)
        if handler:
            return handler.get_metadata(file_path)
        else:
            return {
                "file_type": "unknown",
                "error": f"不支持的文件类型: {Path(file_path).suffix}"
            }

# 注册所有处理器
FileHandlerFactory.register_handler('.pdf', PDFHandler)
FileHandlerFactory.register_handler('.docx', DOCXHandler)
FileHandlerFactory.register_handler('.doc', DOCXHandler)
FileHandlerFactory.register_handler('.xlsx', ExcelHandler)
FileHandlerFactory.register_handler('.xls', ExcelHandler)
FileHandlerFactory.register_handler('.pptx', PPTXHandler)
FileHandlerFactory.register_handler('.ppt', PPTXHandler)
FileHandlerFactory.register_handler('.txt', TextHandler)
FileHandlerFactory.register_handler('.csv', TextHandler)
FileHandlerFactory.register_handler('.png', ImageHandler)
FileHandlerFactory.register_handler('.jpg', ImageHandler)
FileHandlerFactory.register_handler('.jpeg', ImageHandler)
FileHandlerFactory.register_handler('.gif', ImageHandler)
FileHandlerFactory.register_handler('.bmp', ImageHandler)
